package location

import (
	"context"
	"encoding/json"
	"github.com/samber/lo"

	"strings"
	"time"

	"device-admin/config/mysql"
	"device-admin/config/redis"
	"device-admin/internal/app/grpc/client"
	"device-admin/internal/app/grpc/protoc/system_admin"
	"device-admin/internal/app/web/service/device"
	"device-admin/internal/dal"
	"device-admin/internal/dao"
	"device-admin/internal/define"
	"device-admin/internal/models"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/helper"
	"192.168.1.75/go-pkg/logx"
	"github.com/go-playground/validator/v10"
	"gorm.io/gorm"
)

// SetToken 设置商品Token
func SetToken(id string) error {
	uuid, err := helper.UUID{}.String()
	if err != nil {
		logx.Error(context.Background(), "SetToken error", logx.Err(err))
	} else {

		// 1. 获取当前商场下的所有机器, 把使用了当前位置的机器全部加入到开放数据的robot_ids字段中
		var robotInfo = []models.Device{}
		mysql.NewDB().Model(&models.Device{}).
			Where("location_id = ?", id).
			Find(&robotInfo)
		var robotids string = ""
		for _, v := range robotInfo {
			robotids += v.RobotID + ","
		}
		robotids = strings.TrimRight(robotids, ",")
		rowsAffected := mysql.NewDB().Model(&models.Location{}).
			Where("id = ?", id).
			Updates(map[string]interface{}{
				"token":     helper.Md5(uuid),
				"robot_ids": robotids,
			}).RowsAffected
		if rowsAffected > 0 {
			return nil
		}
	}
	return errorx.New("设置失败", -1)
}

// Disable 禁用商品Token -- 把Token值变成0就行
func DisableToken(id string) error {
	rowsAffected := mysql.NewDB().Model(&models.Location{}).Where("id = ?", id).
		Updates(map[string]interface{}{
			"token": "",
		}).RowsAffected
	if rowsAffected > 0 {
		return nil
	}
	return errorx.New("设置失败", -1)
}

// SetRobotIds 获取商场可查看机器
func SetRobotIds(id string, robotIds string) error {
	// 获取商场的数据
	rowsAffected := mysql.NewDB().Model(&models.Location{}).Where("id = ?", id).
		Updates(map[string]interface{}{
			"robot_ids": robotIds,
		}).RowsAffected
	if rowsAffected > 0 {
		return nil
	}
	return errorx.New("设置失败", -1)
}

// SetLocationPoints 商场积分对接
func SetLocationPoints(LocationID, pointsID, mallID string, Sort int64, BackgroundImage string, PointsValue float64) (err error) {
	if LocationID == "" {
		return errorx.New("位置不能为空", -1)
	}

	if pointsID != "" {
		if _, ok := define.PointsType[pointsID]; !ok {
			return errorx.New("积分对接类型错误", -1)
		}

		if BackgroundImage == "" {
			return errorx.New("支付背景图不能为空", -1)
		}
	}

	// 判断是否存在
	var count int64
	mysql.NewDB().Model(&models.Location{}).
		Where("id = ?", LocationID).
		Count(&count)
	if count <= 0 {
		return errorx.New("位置不存在", -1)
	}
	if Sort < 0 || Sort > 999 {
		return errorx.New("排序错误", -1)
	}

	if BackgroundImage != "" {
		// 文件确认
		systemAdmin, err := client.GetSystemAdminClient()
		if err != nil {
			return errorx.New("系统出错", -1)
		}
		res, _ := systemAdmin.ConfirmFile(context.Background(), &system_admin.ConfirmFileReq{FileUrl: BackgroundImage})
		if res.Code != 0 {
			return errorx.New("系统出错", -1)
		}
		BackgroundImage = res.FileUrl
	}
	var LocationPointsCount int64
	mysql.NewDB().Model(&models.LocationPoints{}).
		Where("location_id = ?", LocationID).
		Count(&LocationPointsCount)
	if LocationPointsCount == 0 {
		var InsertData models.LocationPoints
		InsertData.ID, _ = helper.UUID{}.String()
		InsertData.LocationID = LocationID
		InsertData.PointsID = pointsID
		InsertData.MallID = mallID
		InsertData.Sort = Sort
		InsertData.BackgroundImage = BackgroundImage
		InsertData.PointsValue = PointsValue
		InsertData.CreatedAt = time.Now().Unix()
		mysql.NewDB().Model(&models.LocationPoints{}).Create(&InsertData)
	} else {
		var updateData = make(map[string]interface{})
		updateData["points_id"] = pointsID
		updateData["mall_id"] = mallID
		updateData["sort"] = Sort
		updateData["background_image"] = BackgroundImage
		updateData["points_value"] = PointsValue
		updateData["updated_at"] = time.Now().Unix()
		mysql.NewDB().Model(&models.LocationPoints{}).
			Where("location_id = ?", LocationID).
			Updates(&updateData)
	}
	return
}

type LocationOption struct {
	ID   string `json:"id" gorm:"column:id"`
	Name string `json:"name" gorm:"column:name"`
}

// AllLocation 所有位置列表
func AllLocation(
	ctx context.Context,
	provinceID, cityID, districtID string,
) (list []LocationOption, total int64) {
	var locations []LocationOption
	records, total, err := dao.Location{}.List(
		ctx,
		dal.Q,
		provinceID,
		cityID,
		districtID,
		-1,
		-1,
	)
	if err != nil {
		return nil, 0
	}
	for _, record := range records {
		locations = append(locations, LocationOption{
			ID:   record.ID,
			Name: record.Name,
		})
	}
	return locations, total
}

type LocationListType struct {
	models.Location
	Points struct {
		PointsID        string  `gorm:"-" json:"points_id"`        // 积分对接类型id
		Name            string  `gorm:"-" json:"name"`             // 积分对接类型名称
		Sort            int64   `gorm:"-" json:"sort"`             // 积分对接支付排序
		BackgroundImage string  `gorm:"-" json:"background_image"` // 积分对接支付背景图
		MallID          string  `gorm:"-" json:"mall_id"`          // 积分对接支付商场id
		PointsValue     float64 `gorm:"-" json:"points_value"`     // 积分价值
	} `gorm:"-" json:"points"`
	Province     string `json:"province" gorm:"-"`
	City         string `json:"city" gorm:"-"`
	District     string `json:"district" gorm:"-"`
	Floors       string `json:"floors" gorm:"column:floors"`
	Positions    string `json:"positions" gorm:"column:positions"`
	LocationTags string `json:"location_tags" gorm:"-"`
}

// LocationList 位置列表
func LocationList(
	locationName,
	provinceID, cityID, distinctID string, // 省市区
	page, limit int,
) (
	list []*LocationListType,
	total int64,
) {
	tx := mysql.NewDB().Model(&models.Location{})
	// 查询参数

	locationName = strings.TrimSpace(locationName)
	if locationName != "" {
		tx = tx.Where("location.name LIKE ?", "%"+locationName+"%")
	}
	if provinceID != "" {
		tx = tx.Where("location.province_id IN ?", strings.Split(provinceID, ","))
	}
	if cityID != "" {
		tx = tx.Where("location.city_id IN ?", strings.Split(cityID, ","))
	}
	if distinctID != "" {
		tx = tx.Where("location.district_id IN ?", strings.Split(distinctID, ","))
	}
	tx1 := tx.Session(&gorm.Session{})
	// 记录总数
	tx1.Count(&total)
	// 获取记录
	tx1.Joins("LEFT JOIN floor ON floor.location_id = location.id").
		Joins("LEFT JOIN device_position ON device_position.floor_id = floor.id").
		Select(
			"location.*",
			"group_concat(floor.name ORDER BY floor.name) as floors",
			"group_concat(device_position.name) as positions",
		).
		Group("location.id").
		Offset(dao.GetPageOffset(page, limit)).
		Limit(dao.GetPageLimit(limit)).
		Find(&list)
	// 位置id，区域id数组拼接
	var locationIDs = []string{}
	var areaIDs = []string{}
	for _, v := range list {
		locationIDs = append(locationIDs, v.ID)
		areaIDs = append(areaIDs, v.ProvinceID, v.CityID, v.DistrictID)
	}
	// 获取位置的积分设置
	var PointsMap = make(map[string]models.LocationPoints)
	{
		var LocationPoints []models.LocationPoints
		mysql.NewDB().Model(&models.LocationPoints{}).
			Where("location_id in (?)", locationIDs).
			Where("points_id != 0").
			Find(&LocationPoints)
		for _, v := range LocationPoints {
			PointsMap[v.LocationID] = v
		}
	}
	// 返回积分设置
	for k, v := range list {
		// 积分配置
		var points = struct {
			PointsID        string  `gorm:"-" json:"points_id"`        // 积分对接类型id
			Name            string  `gorm:"-" json:"name"`             // 积分对接类型名称
			Sort            int64   `gorm:"-" json:"sort"`             // 积分对接支付排序
			BackgroundImage string  `gorm:"-" json:"background_image"` // 积分对接支付背景图
			MallID          string  `gorm:"-" json:"mall_id"`          // 积分对接支付商场id
			PointsValue     float64 `gorm:"-" json:"points_value"`     // 积分价值
		}{}
		if _, ok := PointsMap[v.ID]; ok {
			points.PointsID = PointsMap[v.ID].PointsID
			points.Name = define.PointsType[points.PointsID]
			points.Sort = PointsMap[v.ID].Sort
			points.BackgroundImage = PointsMap[v.ID].BackgroundImage
			points.MallID = PointsMap[v.ID].MallID
			points.PointsValue = PointsMap[v.ID].PointsValue
			list[k].Points = points
		}
	}
	// 获取省市区的名称
	{
		cli, err := client.GetSystemAdminClient()
		if err == nil {
			rsp, err := cli.AreaName(context.Background(), &system_admin.AreaNameReq{AreaIds: areaIDs})
			if err == nil && rsp != nil {
				for index, record := range list {
					list[index].Province = rsp.AreaNameMap[record.ProvinceID]
					list[index].City = rsp.AreaNameMap[record.CityID]
					list[index].District = rsp.AreaNameMap[record.DistrictID]
				}
			}
		}
	}
	// 获取位置标签
	{
		var locationTagListMap = make(map[string]string)
		var locationTagList []struct {
			LocationID  string `gorm:"column:location_id"`
			LocationTag string `gorm:"column:location_tag"`
		}
		tx1.Joins("JOIN obj_association ON obj_association.obj_id = location.id").
			Joins("JOIN location_tag ON location_tag.id = obj_association.association_id").
			Select("location.id as location_id", "group_concat(location_tag.name) as location_tag").
			Group("location.id").
			Offset(dao.GetPageOffset(page, limit)).
			Limit(dao.GetPageLimit(limit)).
			Find(&locationTagList)
		for _, record := range locationTagList {
			locationTagListMap[record.LocationID] = record.LocationTag
		}
		for index, record := range list {
			list[index].LocationTags = locationTagListMap[record.ID]
		}
	}
	return list, total
}

// 区域位置列表 AreaLocationList
// 查询范围为商户及商户所有下级
func AreaLocationList(loginUserMerchantID string, loginUserMerchantPath string, merchantIDs string, withoutLocation bool, level int) (interface{}, error) {
	type RetType struct {
		ID    string `json:"id"`
		PID   string `json:"pid"`
		Name  string `json:"name"`
		Level int    `json:"level"`
	}
	var ret []RetType
	// 查询当前用户拥有设备
	var locations []models.Location
	tx := mysql.NewDB().Model(&models.Location{})
	tx.Select(
		"location.id",
		"location.name",
		"location.province_id",
		"location.city_id",
		"location.district_id",
	).
		Group("location.id").
		Find(&locations)

	if len(locations) <= 0 {
		return []string{}, nil
	}

	req := &system_admin.AreaLisRequest{}
	if level == 0 {
		level = 3
	}
	for _, location := range locations {
		var pid string
		switch level {
		case 1:
			req.AreaIDs = append(req.AreaIDs, location.ProvinceID)
			pid = location.ProvinceID
		case 2:
			req.AreaIDs = append(req.AreaIDs, location.ProvinceID, location.CityID)
			pid = location.CityID
		case 3:
			req.AreaIDs = append(req.AreaIDs, location.ProvinceID, location.CityID, location.DistrictID)
			pid = location.DistrictID
		}
		// 是否不带位置信息，默认带
		if !withoutLocation {
			ret = append(ret, RetType{
				ID:    location.ID,
				PID:   pid,
				Name:  location.Name,
				Level: 4,
			})
		}
	}

	// 调取微服务
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	c, err := client.GetSystemAdminClient()
	if err != nil {
		return nil, errorx.New("获取失败", -1)
	}
	req.Level = int32(level)
	res, err := c.AreaList(ctx, req)
	if err != nil {
		return nil, errorx.New("获取失败", -1)
	}
	for _, area := range res.Areas {
		ret = append(ret, RetType{
			ID:    area.ID,
			PID:   area.ParentID,
			Name:  area.Name,
			Level: int(area.Level),
		})
	}

	tree := helper.NewTree("ID", "PID")
	if ret == nil {
		return nil, nil
	}
	m, _ := tree.ListToTree("0", ret)
	return m, nil
}

// 区域位置列表 AreaLocationHasDeviceList
// 查询范围为商户及商户所有下级,过滤没有设备的地址
func AreaLocationHasDeviceList(loginUserMerchantID string, loginUserMerchantPath string, merchantIDs string,
	withoutLocation bool, level int, enableQueryAll bool) (interface{}, error) {
	type RetType struct {
		ID    string `json:"id"`
		PID   string `json:"pid"`
		Name  string `json:"name"`
		Level int    `json:"level"`
	}
	var ret []RetType
	// 查询当前用户拥有设备
	var locations []models.Location
	tx := mysql.NewDB().Model(&models.Location{})
	tx.Select(
		"location.id",
		"location.name",
		"location.province_id",
		"location.city_id",
		"location.district_id",
	).
		Group("location.id").
		Find(&locations)

	if len(locations) <= 0 {
		return []string{}, nil
	}

	if enableQueryAll == false {
		var locationIDs []string
		locationIDs = lo.Map(locations, func(loc models.Location, _ int) string {
			return loc.ID
		})

		//性能优化，由IsLocationUsed改用为DeviceListByLocationUsed，这里能优化0.4秒
		deviceUsedList, err := device.DeviceListByLocationUsed(locationIDs)
		if err != nil {
			logx.Error(context.Background(), err.Error())
			return nil, errorx.New("获取失败", -1)
		}

		locationUsedIDs := lo.Map(deviceUsedList, func(dev models.Device, _ int) string {
			return dev.LocationID
		})

		// Filter out locations that are not in use
		/*性能优化，这里能优化0.4秒
		var filteredLocations []models.Location
		for _, location := range locations {
			isUsed, err := device.IsLocationUsed(location.ID)
			if err != nil {
				continue
			}

			if isUsed {
				filteredLocations = append(filteredLocations, location)
			}

		}*/

		filteredLocations := lo.Filter(locations, func(loc models.Location, _ int) bool {
			return lo.Contains(locationUsedIDs, loc.ID)
		})

		locations = filteredLocations
	}

	req := &system_admin.AreaLisRequest{}
	if level == 0 {
		level = 3
	}
	for _, location := range locations {
		var pid string
		switch level {
		case 1:
			req.AreaIDs = append(req.AreaIDs, location.ProvinceID)
			pid = location.ProvinceID
		case 2:
			req.AreaIDs = append(req.AreaIDs, location.ProvinceID, location.CityID)
			pid = location.CityID
		case 3:
			req.AreaIDs = append(req.AreaIDs, location.ProvinceID, location.CityID, location.DistrictID)
			pid = location.DistrictID
		}
		// 是否不带位置信息，默认带
		if !withoutLocation {
			ret = append(ret, RetType{
				ID:    location.ID,
				PID:   pid,
				Name:  location.Name,
				Level: 4,
			})
		}
	}

	// 调取微服务
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	c, err := client.GetSystemAdminClient()
	if err != nil {
		return nil, errorx.New("获取失败", -1)
	}
	req.Level = int32(level)
	res, err := c.AreaList(ctx, req)
	if err != nil {
		return nil, errorx.New("获取失败", -1)
	}
	for _, area := range res.Areas {
		ret = append(ret, RetType{
			ID:    area.ID,
			PID:   area.ParentID,
			Name:  area.Name,
			Level: int(area.Level),
		})
	}

	tree := helper.NewTree("ID", "PID")
	if ret == nil {
		return nil, nil
	}
	m, _ := tree.ListToTree("0", ret)
	return m, nil
}

// AddLocation 新增位置
// openHours 营业时间
func AddLocation(provinceID, cityID, districtID, locationName, addr string, latitude, longitude float64, openingHours string) (string, error) {
	validate := validator.New()
	// 参数检查
	if provinceID == "" || cityID == "" {
		return "", errorx.New("所属省份或城市不能为空", -1)
	}
	// 判断位置是否已经存在
	var count int64
	mysql.NewDB().Model(&models.Location{}).Where(&models.Location{
		Name: locationName,
	}).Count(&count)
	if count > 0 {
		return "", errorx.New("位置已存在", -1)
	}
	// 新增记录
	var locationCreated models.Location
	locationCreated.Name = locationName
	locationCreated.ProvinceID = provinceID
	locationCreated.CityID = cityID
	locationCreated.DistrictID = districtID
	locationCreated.Addr = addr
	// 添加位置的经纬度信息
	if latitude > 0 && longitude > 0 {
		locationCreated.Latitude = latitude
		locationCreated.Longitude = longitude
	}
	// 营业时间校验
	if openingHours != "" {
		hours := strings.Split(openingHours, "-")
		if len(hours) != 2 {
			return "", errorx.New("无效的营业时间", -1)
		}
		if validate.Var(hours[0], "datetime=15:04") != nil || validate.Var(hours[1], "datetime=15:04") != nil {
			return "", errorx.New("无效的营业时间", -1)
		}
		locationCreated.OpeningHours = openingHours
	}
	rowsAffected := mysql.NewDB().Model(&models.Location{}).Create(&locationCreated).RowsAffected
	if rowsAffected <= 0 {
		return "", errorx.New("新增位置失败", -1)
	}
	LoadLocationToRedis(locationCreated.ID)
	return locationCreated.ID, nil
}

// SetLocationNavURL 设置位置的外部导航链接
func SetNavURL(locationID, navURL string) error {
	db := mysql.NewDB()
	// 更新导航url
	db.Model(&models.Location{}).
		Where("id = ?", locationID).
		Updates(map[string]interface{}{
			"nav_url": navURL,
		})
	return nil
}

// GetNavURL 获取导航路径
func GetNavURL(ctx context.Context, robotID, dstShopNO string) (string, error) {
	deviceDetail, err := dao.Device{}.Detail(ctx, dal.Q, robotID)
	if err != nil {
		return "", err
	}
	locationDetail, _ := dao.Location{}.Detail(ctx, dal.Q, deviceDetail.LocationID)
	if locationDetail.NavURL != "" {
		return strings.ReplaceAll(locationDetail.NavURL, "{{end}}", dstShopNO), nil
	}
	return "", nil
}

// LocationDetail 获取位置详情
func LocationDetail(locationID string) models.Location {
	db := mysql.NewDB()
	var location models.Location
	db.Model(&models.Location{}).Where("id = ?", locationID).Take(&location)
	return location
}

// DeleteLocation 删除位置
func DeleteLocation(locationID string) error {
	db := mysql.NewDB()
	// 判断位置是否存在
	var count int64
	db.Model(&models.Location{}).Where(models.Location{
		ID: locationID,
	}).Count(&count)
	if count <= 0 {
		return errorx.New("位置不存在", -1)
	}
	// 在使用的位置不能删除
	db.Model(&models.Device{}).Where(models.Device{
		LocationID: locationID,
	}).Count(&count)
	if count > 0 {
		return errorx.New("正在被使用，不能删除", -1)
	}
	// 删除
	rowsAffected := db.Model(&models.Location{}).
		Where(models.Location{
			ID: locationID,
		}).
		Delete(&models.Location{}).
		RowsAffected
	if rowsAffected <= 0 {
		return errorx.New("删除失败", -1)
	}
	LoadAllLocationToRedis()
	return nil
}

// EditLocation 编辑位置
func EditLocation(locationID, proviceID, cityID, districtID, locationName, addr string, latitude, longitude float64, openingHours string) error {
	validate := validator.New()
	// 判断记录是否存在
	{
		var count int64
		mysql.NewDB().Model(&models.Location{}).
			Where("id = ?", locationID).
			Count(&count)
		if count <= 0 {
			return errorx.New("编辑的位置不存在", -1)
		}
	}

	// 更新内容
	var locationUpdated models.Location
	if proviceID != "" {
		locationUpdated.ProvinceID = proviceID
	}
	if cityID != "" {
		locationUpdated.CityID = cityID
	}
	if districtID != "" {
		locationUpdated.DistrictID = districtID
	}
	if locationName != "" {
		var temp models.Location
		// 判断位置名字是否已经存在
		rowsAffected := mysql.NewDB().Model(&models.Location{}).
			Where(&models.Location{Name: locationName}).
			Take(&temp).
			RowsAffected
		if rowsAffected > 0 && temp.ID != locationID {
			return errorx.New("位置已存在", -1)
		}
		locationUpdated.Name = locationName
	}
	locationUpdated.Addr = addr
	// 更新经纬度
	if latitude > 0 && longitude > 0 {
		locationUpdated.Latitude = latitude
		locationUpdated.Longitude = longitude
	}
	// 营业时间校验
	if openingHours != "" {
		hours := strings.Split(openingHours, "-")
		if len(hours) != 2 {
			return errorx.New("无效的营业时间", -1)
		}
		if validate.Var(hours[0], "datetime=15:04") != nil || validate.Var(hours[1], "datetime=15:04") != nil {
			return errorx.New("无效的营业时间", -1)
		}
		locationUpdated.OpeningHours = openingHours
	}
	// 更新位置
	rowsAffected := mysql.NewDB().Model(&models.Location{}).
		Where(&models.Location{ID: locationID}).
		Updates(&locationUpdated).
		RowsAffected
	if rowsAffected <= 0 {
		return errorx.New("更新失败", -1)
	}
	LoadLocationToRedis(locationID)
	return nil
}

// EnableLocationNav 开启商场导航
func EnableLocationNav(locationID string) error {
	db := mysql.NewDB()
	var count int64
	db.Model(&models.Location{}).Where("id = ?", locationID).Count(&count)
	if count <= 0 {
		return errorx.New("位置不存在", -1)
	}
	rowsAffected := db.Model(&models.Location{}).
		Where("id = ?", locationID).
		Update("enable_nav", 1).RowsAffected
	if rowsAffected <= 0 {
		return errorx.New("新建商场导航失败", -1)
	}
	return nil
}

// UpdateLocationBrands 批量更新商场品牌
func UpdateLocationBrands(brandIDs, floorID string) (successCount int64, err error) {
	db := mysql.NewDB()

	// 判断楼层是否存在
	{
		var count int64
		db.Model(&models.Floor{}).Where("id = ?", floorID).Count(&count)
		if count <= 0 {
			return 0, errorx.New("楼层不存在", -1)
		}
	}

	// 批量更新
	{
		brandIDArr := strings.Split(brandIDs, ",")
		for _, brandID := range brandIDArr {
			var brand models.Brand
			db.Model(&models.Brand{}).Where("id = ?", brandID).Take(&brand)
			var rowsAffected int64
			// 公共品牌
			if brand.LocationID == "" {
				// 不存在就创建
				rowsAffected = db.Model(&models.FloorBrand{}).
					Where(models.FloorBrand{
						BrandID: brandID,
						FloorID: floorID,
					}).
					FirstOrCreate(&models.FloorBrand{}).RowsAffected
			} else { // 私有品牌
				// 存在品牌就更新，不存在就创建
				rowsAffected = db.Model(&models.FloorBrand{}).
					Where(models.FloorBrand{
						BrandID: brandID,
					}).
					Assign(models.FloorBrand{
						FloorID: floorID,
					}).
					FirstOrCreate(&models.FloorBrand{}).RowsAffected
			}
			if rowsAffected == 1 {
				successCount++
			}
		}
	}
	return successCount, nil
}

type LocationNavType struct {
	ID         string `json:"id" gorm:"column:id"`
	Name       string `json:"name" gorm:"column:name"`
	ProvinceID string `json:"province_id" gorm:"column:province_id"`
	NavURL     string `json:"nav_url" gorm:"column:nav_url"`
	CityID     string `json:"city_id" gorm:"column:city_id"`
	DistrictID string `json:"district_id" gorm:"column:district_id"`
	TotalMap   int64  `json:"total_map" gorm:"column:total_map"`
	TotalBrand int64  `json:"total_brand" gorm:"column:total_brand"`
}

// LocationNavList 位置导航列表
// 显示所在省市区，以及具体的位置，包含的地图数量，品牌数
func LocationNavList(locationID string, page, limit int) (list []LocationNavType, total int64, err error) {
	db := mysql.NewDB()
	tx := db.Model(&models.Location{}).
		Joins("LEFT JOIN brand ON brand.location_id = location.id"). // 私有品牌
		Joins("LEFT JOIN floor ON floor.location_id = location.id"). // 楼层地图
		Select(
			"location.id",
			"location.name",
			"location.province_id",
			"location.nav_url",
			"location.city_id",
			"location.district_id",
			"COUNT(distinct floor.map) as total_map",
			"COUNT(distinct brand.id) as total_brand",
		).
		Where(
			db.Where("location.enable_nav = ?", 1).Or("floor.map IS NOT NULL AND floor.map <> ''"),
		).
		Group("location.id")

	if locationID != "" {
		tx = tx.Where("location.id = ?", locationID)
	}

	tx.Count(&total)

	tx = helper.Gorm{}.Paginate(tx, page, limit)
	tx.Find(&list)
	return list, total, err
}

// LoadLocationToRedis 加载位置信息到redis
func LoadLocationToRedis(locationID string) {
	var locations []struct {
		ID   string `json:"id" gorm:"column:id"`
		Name string `json:"name" gorm:"column:name"`
	}
	tx := mysql.NewDB().Model(&models.Location{})
	if locationID != "" {
		tx.Where("id = ?", locationID)
	}
	tx.Select("id", "name").Find(&locations)
	if len(locations) > 0 {
		var values []interface{}
		for _, location := range locations {
			dataBytes, _ := json.Marshal(location)
			values = append(values, location.ID, string(dataBytes))
		}

		ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
		defer cancel()
		_, err := redis.NewDB().HMSet(ctx, define.RedisLocationList, values...).Result()
		if err != nil {
			logx.Error(context.Background(), "LoadLocationToRedis", logx.Err(err))
		}
	}
}

// LoadDeviceToRedis 加载设备列表到redis缓存
func LoadAllLocationToRedis() {
	LoadLocationToRedis("")
}
